#pragma once
#include "Reactor.hpp"
#include "Util.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <vector>
#include <string>
using ns_reactor::Event;

// 网络就绪事件与事件派发，和网络数据读取进行解耦

/*
参数：
    out：输出型参数
    sock：对应的文件描述符
返回值:
    0：代表本轮读取数据成功完毕
    -1：代表本轮读取出错
*/
static int RecvHelper(int sock, std::string *out)
{
    char buffer[1024];
    buffer[0] = 0;
    while (true)
    {
        ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (s > 0)
        {
            // 读取到数据
            buffer[s] = 0;
            (*out) += buffer;
        }
        else if (s < 0)
        {
            if (errno == EINTR)
            {
                continue; // 信号中断，继续读取
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                return 0; // 底层数据读取完毕，退出
            }
            else
            {
                return -1; // 读取出错
            }
        }
        else
        {
            // s=0 代表对端已经关闭
            return -1;
        }
    }
}

void Recver(Event &event)
{
    std::cout << "call Recver..." << std::endl;
    // 先把就绪数据从底层读取
    if (-1 == RecvHelper(event.sock_, &(event.inbuffer_)))
    {
        // 本轮读取出错(sock对端关闭了，sock读取数据出错了)
        if (event.error_callback_)
            event.error_callback_(event);
        return;
    }

    // 进行业务处理
    // 所有数据全部都已经在inbuffer中(未来的，现在的)
    // 1.分隔协议，解决粘包问题
    // 2.报文解析，处理结果
    // 3.构建报文，输出结果
    // 暂定协议，1+2X3+8X10+2X, 类似1+1为每个报文，X为每个报文之间的分隔符

    //将数据中的空格去除掉
    Util::RemoveSpace(event.inbuffer_);
    // 1. 将inbuffer中数据拆这一个个的报文
    std::vector<std::string> packages;
    Util::StringSplit(event.inbuffer_, &packages, "X");

    // 2. packages中的每个报文进行协议解析
    // packages不一定有着数据存在，如果未来的和现在的数据不构成一个完整的报文
    if (packages.size() != 0)
    {
        for (auto &package : packages)
        {
            // 进行反序列化
            int x = 0;
            int y = 0;
            char op = 0;

            Util::ParsePackage(package, &x, &y, &op);
            // 执行业务处理
            int result = 0;
            switch (op)
            {
            case '+':
                result = x + y;
                break;
            case '-':
                result = x - y;
                break;
            case '*':
                result = x * y;
                break;
            case '/':
                result = x / y;
                break;
            default:
                break;
            }
            // 构建返回报文
            std::string response = package;
            response += "=";
            response += std::to_string(result);
            response += "X";
            // 输出给outbuffer中
            event.outbuffer_ += response;
        }
        // 设置该文件描述符，让其检测写数据--不能直接输送返回报文
        event.r_->EnableReadWrite(event.sock_, true, true);
    }
}

/*
参数：
    sock：对应的文件描述符
    out_buffer：将要输出的数据buffer
返回值：
    ret > 0 :缓冲区全部发完
    ret == 0:本轮发送完，但缓冲区还有数据
    ret < 0 :发送失败
*/
int SenderHelper(int sock, std::string &out_buffer)
{
    int total = 0; // 表示总共发了多少次
    const char *start = out_buffer.c_str();
    int size = out_buffer.size(); // 代表发送缓冲区数据总数
    while (true)
    {
        // 并不知道写事件就绪时可以发送多少
        ssize_t s = send(sock, start + total, size - total, 0);
        if (s > 0)
        {
            // 成功发送
            total += s;
            if (total == size)
            {
                // 代表数据发送全部完成
                out_buffer.clear();
                return 1;
            }
        }
        else
        {
            if (errno == EINTR)
            {
                // 信号中断
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 底层发送缓冲区已经满了，暂时退出，等事件就绪
                out_buffer.erase(0, total);
                return 0;
            }
            else
            {
                return -1; // 发送失败
            }
        }
    }
}
void Sender(Event &event)
{
    std::cout << "call Sender..." << std::endl;
    // 发送数据
    int ret = SenderHelper(event.sock_, event.outbuffer_);
    switch (ret)
    {
    case 1:
        // outbuffer全部发送
        event.r_->EnableReadWrite(event.sock_, true, false);
        break;
    case 0:
        // 本轮发送成功，但还有数据，让其等待写事件就绪
        event.r_->EnableReadWrite(event.sock_, true, true);
        break;
    case -1:
        // 发送失败
        if (event.error_callback_)
            event.error_callback_(event);
        break;
    default:
        break;
    }
}

void Errorer(Event &event)
{
    std::cout << "call Errorer..." << std::endl;
    // 出错，关闭此链接
    event.r_->DelEvent(event.sock_);
}